﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using XieCan.AspMVC.Models;

namespace XieCan.AspMVC.IService
{
    /// <summary>
    /// 公共的数据操作接口
    /// </summary>
    /// <typeparam name="TModel">继承自BaseModel的所有类型</typeparam>
    public interface IBaseService<TModel> : IServiceSupport where TModel : BaseModel
    {
        /// <summary>
        /// 执行查询语句
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="sql">查询语句</param>
        /// <param name="parameters">SQL参数</param>
        /// <returns>查询结果的可枚举集合</returns>
        OperateResult<IEnumerable<T>> ExecQuery<T>(string sql, params SqlParameter[] parameters);

        /// <summary>
        /// 执行非查询语句
        /// </summary>
        /// <param name="sql">非查询语句</param>
        /// <param name="parameters">SQL参数</param>
        /// <returns>受影响的行</returns>
        OperateResult<int> ExecNonQuery(string sql, params SqlParameter[] parameters);

        /// <summary>
        /// 开启事务
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        OperateResult<bool> BeginTransaction(IsolationLevel level = IsolationLevel.Chaos);

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="models"></param>
        /// <remarks>不会自动保存，需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> Insert(params TModel[] models);

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="models"></param>
        /// <remarks>会自动保存，无需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> InsertChanges(params TModel[] models);

        /// <summary>
        /// 删除实体（软删除）
        /// </summary>
        /// <param name="models"></param>
        /// <remarks>不会自动保存，需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> Delete(params TModel[] models);

        /// <summary>
        /// 删除实体（软删除）
        /// </summary>
        /// <param name="models"></param>
        /// <remarks>会自动保存，无需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> DeleteChanges(params TModel[] models);

        /// <summary>
        /// 删除实体（软删除）
        /// </summary>
        /// <param name="ids"></param>
        /// <remarks>不会自动保存，需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> Delete(params string[] ids);

        /// <summary>
        /// 删除实体（软删除）
        /// </summary>
        /// <param name="ids"></param>
        /// <remarks>会自动保存，无需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> DeleteChanges(params string[] ids);

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="properties">需要修改的属性集合，用英文,号隔开，区分大小写</param>
        /// <param name="models"></param>
        /// <remarks>不会自动保存，需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> Update(string properties = "", params TModel[] models);

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="properties">需要修改的属性集合，用英文,号隔开，区分大小写</param>
        /// <param name="models"></param>
        /// <remarks>会自动保存，无需显式调用SaveChanges()</remarks>
        /// <returns></returns>
        OperateResult<bool> UpdateChanges(string properties = "", params TModel[] models);

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <param name="guid">主键</param>
        /// <returns></returns>
        OperateResult<TModel> Find(string guid);

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <param name="guid">主键</param>
        /// <returns></returns>
        OperateResult<TModel> Find(Guid guid);

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <param name="guid">主键</param>
        /// <returns></returns>
        Task<OperateResult<TModel>> FindAsync(Guid guid);

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <param name="where">条件过滤</param>
        /// <returns></returns>
        OperateResult<TModel> Find(Expression<Func<TModel, bool>> where);

        /// <summary>
        /// 查询单个实体
        /// </summary>
        /// <param name="where">条件过滤</param>
        /// <returns></returns>
        Task<OperateResult<TModel>> FindAsync(Expression<Func<TModel, bool>> whereLambda);

        /// <summary>
        /// 查询列表
        /// </summary>
        /// <returns></returns>
        OperateResult<IQueryable<TModel>> Select();

        /// <summary>
        /// 查询列表
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        OperateResult<IQueryable<TModel>> Select(Expression<Func<TModel, bool>> where);

        /// <summary>
        /// 查询列表带排序
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="where"></param>
        /// <param name="order"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        OperateResult<IQueryable<TModel>> Select<TKey>(Expression<Func<TModel, bool>> where, Expression<Func<TModel, TKey>> order, bool isAsc = true);

        /// <summary>
        /// 查询列表带分页
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="pageIndex">当前页面</param>
        /// <param name="take">单页显示数量</param>
        /// <param name="rowCount">数据总数</param>
        /// <param name="pageCount">总页数</param>
        /// <param name="where"></param>
        /// <param name="order"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        OperateResult<IQueryable<TModel>> Select<TKey>(Expression<Func<TModel, bool>> where, Expression<Func<TModel, TKey>> order, out long rowCount, out long pageCount, bool isAsc = true, long pageIndex = 1, int pageSize = 12);

        /// <summary>
        /// 保存更改
        /// </summary>
        /// <returns></returns>
        OperateResult<bool> SaveChanges();

        /// <summary>
        /// 保存更改
        /// </summary>
        /// <returns></returns>
        Task<OperateResult<bool>> SaveChangesAsync();
    }
}
